package cn.wangzg.course0501;

import android.util.Xml;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.reflect.TypeToken;

import org.json.JSONArray;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlPullParser;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

/**
 * Time: 2020/3/17
 * Author: wangzhiguo
 * Description: 功能描述
 */
public class WeatherService {
    //解析xml文件返回天气信息的集合 pull解析
    public static List<WeatherInfo> getInfosFromXML(InputStream is)
            throws Exception {
        //1.得到pull解析器
        XmlPullParser parser = Xml.newPullParser();
        //2. 初始化解析器,第一个参数代表包含xml的数据
        parser.setInput(is, "utf-8");
        List<WeatherInfo> weatherInfos = null;
        WeatherInfo weatherInfo = null;
        //3.得到当前事件的类型
        int type = parser.getEventType();
        // END_DOCUMENT文档结束标签
        while (type != XmlPullParser.END_DOCUMENT) {
            switch (type) {
                //一个节点的开始标签
                case XmlPullParser.START_TAG:
                    //解析到全局开始的标签 infos 根节点
                    if ("infos".equals(parser.getName())) {
                        weatherInfos = new ArrayList<WeatherInfo>();
                    } else if ("city".equals(parser.getName())) {
                        weatherInfo = new WeatherInfo();
                        String idStr = parser.getAttributeValue(0);
                        weatherInfo.setId(idStr);
                    } else if ("temp".equals(parser.getName())) {
                        //parset.nextText()得到该tag节点中的内容
                        String temp = parser.nextText();
                        weatherInfo.setTemp(temp);
                    } else if ("weather".equals(parser.getName())) {
                        String weather = parser.nextText();
                        weatherInfo.setWeather(weather);
                    } else if ("name".equals(parser.getName())) {
                        String name = parser.nextText();
                        weatherInfo.setName(name);
                    } else if ("pm".equals(parser.getName())) {
                        String pm = parser.nextText();
                        weatherInfo.setPm(pm);
                    } else if ("wind".equals(parser.getName())) {
                        String wind = parser.nextText();
                        weatherInfo.setWind(wind);
                    }
                    break;
                //一个节点结束的标签
                case XmlPullParser.END_TAG:
                    //一个城市的信息处理完毕，city的结束标签
                    if ("city".equals(parser.getName())) {
                        weatherInfos.add(weatherInfo);
                        weatherInfo = null;
                    }
                    break;
            }
            type = parser.next();//下一个事件的类型
        }
        return weatherInfos;
    }

    /**
     * 解析json文件返回天气信息的集合
     * [
     *   {"temp":"20℃/30℃","weather":"晴转多云","name":"上海","pm":"80","wind":"1级"},
     *   {"temp":"15℃/24℃","weather":"晴","name":"北京","pm":"98","wind":"3级"},
     *   {"temp":"26℃/32℃","weather":"多云","name":"广州","pm":"30","wind":"2级"}
     * ]
     * @param is 输入流
     * @return 城市天气列表
     * @throws Exception
     */
    public static List<WeatherInfo> getInfosFromJson(InputStream is)
            throws Exception {
        List<WeatherInfo> weatherInfos=new ArrayList<>();
        WeatherInfo info;
        //字节流-->字符串
        byte[] buffer = new byte[is.available()];
        is.read(buffer);
        String json = new String(buffer, "utf-8");
        /**
         * 1.[]  JSONArray array=new JSONArray(json);
         * 2.{}  JSONObject obj=new JSONObject(json);
         * 3.optJSONArray、optJSONObject
         * optString
         */
        JSONArray array=new JSONArray(json);
        for (int i = 0; i < array.length(); i++) {
            JSONObject object=array.optJSONObject(i);//官方建议
            //JSONObject object=array.getJSONObject(i);
            info=new WeatherInfo();
            info.setWind(object.optString("wind"));
            info.setTemp(object.optString("temp"));
            info.setName(object.optString("name"));
            info.setPm(object.optString("pm"));
            info.setWeather(object.getString("weather"));
            weatherInfos.add(info);
        }
        return weatherInfos;
    }
    //解析json文件返回天气信息的集合
    public static List<WeatherInfo> getInfosFromJsonByGson(InputStream is)
            throws IOException {
        byte[] buffer = new byte[is.available()];
        is.read(buffer);
        String json = new String(buffer, "utf-8");

        //使用gson库解析JSON数据
        Gson gson = new Gson();
        List<WeatherInfo> weatherInfos = gson.fromJson(json, new TypeToken<List<WeatherInfo>>() {
        }.getType());
        return weatherInfos;
    }

    //使用SAX解析Xml
    public static List<WeatherInfo> parseXMLWithSAX(InputStream is) {
        try {
            //①创建XML解析处理器
            CustomContentHandler handler = new CustomContentHandler();
            //②得到SAX解析工厂
            SAXParserFactory factory = SAXParserFactory.newInstance();
            //③创建SAX解析器
            SAXParser saxParser = factory.newSAXParser();
            //④将xml解析处理器分配给解析器,对文档进行解析,将事件发送给处理器
            saxParser.parse(is, handler);
            is.close();
            return handler.getInfos();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    static class CustomContentHandler extends DefaultHandler {
        WeatherInfo info;
        List<WeatherInfo> infos;
        //当前解析的元素标签
        private String tagName = null;

        public List<WeatherInfo> getInfos() {
            return infos;
        }
        /**
         * 当读取到文档开始标志是触发，通常在这里完成一些初始化操作
         */
        @Override
        public void startDocument() throws SAXException {
            infos = new ArrayList<>();
        }
        //读到一个开始标签时调用,第二个参数为标签名,最后一个参数为属性数组
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if ("city".equals(localName)) {
                info = new WeatherInfo();
                info.setId(attributes.getValue("id"));
            }
            this.tagName = localName;
        }
        //读到到内容,第一个参数为字符串内容,后面依次为起始位置与长度
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            //判断当前标签是否有效
            if (this.tagName != null) {
                String data = new String(ch, start, length);
                if (tagName.equals("name")) {
                    info.setName(data);
                } else if (tagName.equals("pm")) {
                    info.setPm(data);
                } else if (tagName.equals("temp")) {
                    info.setTemp(data);
                } else if (tagName.equals("weather")) {
                    info.setWeather(data);
                } else if (tagName.equals("wind")) {
                    info.setWind(data);
                }
            }
        }
        //处理元素结束时触发,这里将对象添加到列表中
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if (localName.equals("city")) {
                this.infos.add(info);
                info = null;
            }
            this.tagName = null;
        }

        @Override
        public void endDocument() throws SAXException {
            super.endDocument();
        }
    }


    //解析xml文件返回天气信息的集合
    public static List<WeatherInfo> parseXMLWithDom(InputStream is)
            throws Exception {
        ArrayList<WeatherInfo> infos = new ArrayList<>();
        //①获得DOM解析器的工厂示例:
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        //②从Dom工厂中获得dom解析器
        DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
        //③把要解析的xml文件读入Dom解析器
        Document doc = dbBuilder.parse(is);
        //④得到文档中名称为person的元素的结点列表
        NodeList nList = doc.getElementsByTagName("city");
        //⑤遍历该集合,显示集合中的元素以及子元素的名字
        for (int i = 0; i < nList.getLength(); i++) {
            //先从Person元素开始解析
            Element infoElement = (Element) nList.item(i);
            WeatherInfo info = new WeatherInfo();
            info.setId(infoElement.getAttribute("id"));

            //获取person下的name和age的Note集合
            NodeList childNoList = infoElement.getChildNodes();
            for (int j = 0; j < childNoList.getLength(); j++) {
                Node childNode = childNoList.item(j);
                //判断子note类型是否为元素Note
                if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element childElement = (Element) childNode;
                    if ("name".equals(childElement.getNodeName()))
                        info.setName(childElement.getFirstChild().getNodeValue());
                    else if ("weather".equals(childElement.getNodeName()))
                        info.setWeather(childElement.getFirstChild().getNodeValue());
                    else if ("pm".equals(childElement.getNodeName()))
                        info.setPm(childElement.getFirstChild().getNodeValue());
                    else if ("temp".equals(childElement.getNodeName()))
                        info.setTemp(childElement.getFirstChild().getNodeValue());
                    else if ("wind".equals(childElement.getNodeName()))
                        info.setWind(childElement.getFirstChild().getNodeValue());
                }
            }
            infos.add(info);
        }
        return infos;
    }
}
